﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace PronosGestor
{
    /// <summary>
    /// Fournit les méthodes de calcul de diverses statistiques de pronostics.
    /// Des éléments sont également stockés, tel que les classements de chaque journée
    /// </summary>
    public partial class StatsGenerales
    {
        public Dictionary<string, DonneesCompletesClassement> Classement { get; set; }
        public Dictionary<string, int> ClassementVainqueurs { get; set; }
        public List<Dictionary<string, DonneesCompletesClassement>> ClassementsJournees { get; set; }
        public Dictionary<string, List<DonneesClassementEquipe>> ClassementEquipesPronos { get; set; }

        // Qui a remporté une journée avec le plus grand nombre de points ?
        public KeyValuePair<List<string>, int> MeilleureVictoire
        {
            get
            {
                var max = VainqueursEtPoints.Max(y => y.Value);
                var liste = VainqueursEtPoints.Where(x => x.Value == max);
                var listeVainqueurs = new List<string>();

                foreach (var item in liste)
                {
                    listeVainqueurs.Add(item.Key);
                }

                return new KeyValuePair<List<string>, int>(listeVainqueurs, max);
            }
        }

        // Qui détient le plus grand nombre de résultats trouvés en une journée ?
        public KeyValuePair<List<string>, Int32> PlusDeResultatsTrouvesJournee
        {
            get
            {
                // récupération du max
                int max = ClassementsJournees.Select(x => x.Values.Max(y => y.NombreResultatsBons)).Max();
                return DonnerRecord(x => x.NombreResultatsBons, max);
            }
        }

        // Qui détient le plus grand nombre de scores exacts trouvés en une journée ?
        public KeyValuePair<List<string>, Int32> PlusDeScoresExtactsTrouvesJournee
        {
            get
            {
                // récupération du max
                int max = ClassementsJournees.Select(x => x.Values.Max(y => y.NombreScoresExacts)).Max();
                return DonnerRecord(x => x.NombreScoresExacts, max);
            }
        }

        // Qui détient le plus gros total de gains virtuels en une journée ?
        public KeyValuePair<List<string>, Double> PlusGrosGainVirtuelJournee
        {
            get
            {
                // récupération du max
                double max = ClassementsJournees.Select(x => x.Values.Max(y => y.GainsVirtuels)).Max();
                return DonnerRecord(x => x.GainsVirtuels, max);
            }
        }

        public StatsGenerales()
        {
            this.Classement = new Dictionary<string, DonneesCompletesClassement>();
            this.ClassementVainqueurs = new Dictionary<string, int>();
            this.ClassementsJournees = new List<Dictionary<string, DonneesCompletesClassement>>();

            VainqueursEtPoints = new Dictionary<string, int>();
        }

        public void ConstituerClassementGeneral(List<Participant> participants)
        {
            foreach (var participant in participants)
            {
                var donnees = new DonneesCompletesClassement()
                {
                    Points = participant.TotalPoints(),
                    GainsVirtuels = participant.TotalGainsVirtuels(),
                    NombreResultatsBons = participant.TotalResultatsBons(),
                    NombreScoresExacts = participant.TotalScoresExacts(),
                    NombrePronostics = participant.TotalPronostics(),
                    NombreJourneesCompletes = participant.TotalJourneesCompletes(),
                    NombreVictoires = DonnerNombreVictoiresJoueur(participant)
                };
                this.Classement.Add(participant.nom, donnees);
            }

            this.Classement = this.Classement.OrderByDescending(x => x.Value.Points).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value);
        }

        public void ConstituerClassementGeneralParJournee(List<Participant> participants, List<JourneeJouee> journees)
        {
            foreach (var journee in journees)
            {
                var result = new Dictionary<string, DonneesCompletesClassement>();

                foreach (var participant in participants)
                {
                    var donnees = new DonneesCompletesClassement()
                    {
                        Points = participant.TotalPoints(journee.IDJournee),
                        GainsVirtuels = participant.TotalGainsVirtuels(journee.IDJournee),
                        NombreResultatsBons = participant.TotalResultatsBons(journee.IDJournee),
                        NombreScoresExacts = participant.TotalScoresExacts(journee.IDJournee),
                        NombrePronostics = participant.TotalPronostics(journee.IDJournee),
                    };
                    result.Add(participant.nom, donnees);
                }

                result = result.OrderByDescending(x => x.Value.Points).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value);
                ClassementsJournees.Add(result);
            }
        }

        public void ConstituerClassementVainqueurs(List<Participant> participants, List<JourneeJouee> journees)
        {         
            // Mise à plat de toutes les journées pronostiquées
            var allJourneesPronostiquees = MiseAPlatJourneesPronos(participants);

            // Pour chaque journée, détermination du / des vainqueurs
            DeterminerVainqueursJournees(journees, allJourneesPronostiquees);

            this.ClassementVainqueurs = this.ClassementVainqueurs.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value);
        }

        public void ConstituerClassementsEquipesParPronos(List<Participant> participants, List<string> equipes, int nbJourneesJoueesTotal)
        {
            ClassementEquipesPronos = new Dictionary<string, List<DonneesClassementEquipe>>();

            foreach (var joueur in participants)
            {
                // Initialisation du classement
                var classement = new List<DonneesClassementEquipe>();

                // Alimentation du classement avec la liste des équipes
                foreach (var equipe in equipes)
                {
                    classement.Add(new DonneesClassementEquipe() { Equipe = equipe });
                }

                // Parcours des journées pronostiquées
                foreach (var journeeProno in joueur.JourneesPronostiquees)
                {
                    var i = 1;
                    // Parcours de chaque match
                    foreach (var match in journeeProno.MatchsJournee)
                    {
                        if (i <= nbJourneesJoueesTotal)
                        {
                            if (match.EstMatchPronstique)
                            {
                                var equipeDomicile = classement.Where(x => x.Equipe == match.EquipeDomicile).First();
                                var equipeExterieur = classement.Where(x => x.Equipe == match.EquipeExterieur).First();

                                switch (match.ResultatMatch.TypeResultat)
                                {
                                    case '1':
                                        equipeDomicile.Victoires += 1;
                                        equipeExterieur.Defaites += 1;
                                        break;
                                    case 'N':
                                        equipeDomicile.Nuls += 1;
                                        equipeExterieur.Nuls += 1;
                                        break;
                                    case '2':
                                        equipeExterieur.Victoires += 1;
                                        equipeDomicile.Defaites += 1;
                                        break;
                                    default:
                                        break;
                                }

                                equipeDomicile.ButsMarques += Convert.ToInt32(match.ResultatMatch.ScoreDomicile);
                                equipeDomicile.ButsEncaisses += Convert.ToInt32(match.ResultatMatch.ScoreExterieur);
                                equipeExterieur.ButsMarques += Convert.ToInt32(match.ResultatMatch.ScoreExterieur);
                                equipeExterieur.ButsEncaisses += Convert.ToInt32(match.ResultatMatch.ScoreDomicile);
                            }
                        }
                        i++;
                    }
                }

                ClassementEquipesPronos.Add(joueur.nom, classement);
            }
        }
    }

    public class DonneesCompletesClassement
    {
        public int Points { get; set; }
        public double GainsVirtuels { get; set; }
        public int NombreResultatsBons { get; set; } // 1 / N / 2
        public int NombreScoresExacts { get; set; } // inclus dans NombreResultatsBons
        public int NombrePronostics { get; set; }
        public int NombreJourneesCompletes { get; set; }
        public int NombreVictoires { get; set; }

        public DonneesCompletesClassement()
        {
        }

        public double CalculerEfficience()
        {
            return Convert.ToDouble(NombreResultatsBons) / Convert.ToDouble(NombrePronostics);
        }

        public double CalculerMoyennePointsParJournee()
        {
            return Convert.ToDouble(Points) / NombrePronostics * 10;
        }
    }

    public class DonneesClassementEquipe
    {
        public string Equipe { get; set; }
        public int Victoires { get; set; }
        public int Nuls { get; set; }
        public int Defaites { get; set; }
        public int ButsMarques { get; set; }
        public int ButsEncaisses { get; set; }

        public int GoalAverage
        {
            get
            {
                return this.ButsMarques - this.ButsEncaisses;
            }
        }

        public int MatchsJoues
        {
            get
            {
                return this.Victoires + this.Nuls + this.Defaites;
            }
        }

        public int Points
        {
            get
            {
                return this.Victoires * 3 + this.Nuls;
            }
        }

        public DonneesClassementEquipe()
        {

        }
    }
}
